#include "gameroom.h"
#include "gameselect.h"
#include "utility.hpp"
#include <QIcon>
#include <QPainter>
#include <QPixmap>
#include <QDebug>
#include <QPushButton>
#include <QTimer>
#include <QSound>
#include <QRectF>
#include <QTime>
#include <QMessageBox>
#include <QShortcut>
#include <QDateTime>

gameRoom::gameRoom(QWidget *parent) : QWidget(parent)
{
    this->setAttribute(Qt::WA_DeleteOnClose);

    // 使用当前时间初始化随机数生成器种子
    qsrand(static_cast<uint>(QTime::currentTime().msec()));

    //读取qss文件属性
    const QString &style = utility::ReadFile("C:/Users/LKM/Code/snake-game/Snake/qss/gameRoom/QPushButton.txt");

    //设置窗口大小
    this->resize(1000,800);
    //设置标题
    this->setWindowTitle("游戏房间");
    //设置窗口图标
    this->setWindowIcon(QIcon(":/resource/ico.png"));

    //初始化食物
    food = new QRectF(qrand() % (800 / foodWidget) * foodWidget,\
                      qrand() % (this->height() / foodHeight) * foodHeight,\
                      foodWidget,foodHeight);

    qDebug() << food->x() << ":" <<food->y();

    //初始化蛇
    snakeList.push_back(QRectF(this->width()*0.5,this->height()*0.5,snakeNodeWidget,snakeNodeHeight));
    //通过两次向上移动，向snakeList头插两个节点，以达到初始化蛇有三个节点的效果
    moveTop();
    moveTop();

    //创建定时器
    timer = new QTimer(this);

    //为定时器绑定槽函数
    connect(timer,&QTimer::timeout,[=](){
        //记录吃到的食物数量
        int cnt = 1;

        //判断是否吃到食物
        if(snakeList.front().intersects(*food)){
            //改变食物位置
            food->moveTo(qrand() % (800 / foodWidget) * foodWidget,\
                       qrand() % (this->height() / foodHeight) * foodHeight);

            //播放吃到食物音效
            QSound::play(":/resource/eatfood.wav");

            cnt++;
        }

        //移动蛇 这里while循环默认会执行一次，如果在一次移动中吃到了食物，那么会多移动一次
        //这里调用move系列的函数是会在list头插一个节点的，代表移动了一步，但是并没有尾插，也就造成了蛇节点多了一个
        //所以在我们后面的代码中有一个删除尾节点，但是这个尾节点只会删除一次。
        //也就是说这个当这个cnt>1时，也就是我们吃到了食物，这个move系列的函数会执行多次，而尾删只会执行一次
        //也就实现了吃到食物增加节点的效果
        while(cnt--){
            switch(snakeDirection)
            {
                case Direction::UP : moveTop(); break;
                case Direction::DOWN: moveDown(); break;
                case Direction::LEFT : moveLeft(); break;
                case Direction::RIGHT : moveRight(); break;
            }
        }

        //删除尾节点
        snakeList.pop_back();

        //触发绘制事件，更新游戏信息
        this->update();
    });

    //创建开始和暂停按钮
    QPushButton *startButton = new QPushButton(this);
    QPushButton *stopButton = new QPushButton(this);
    startButton->setText("开 始");
    stopButton->setText("暂 停");
    startButton->move(855,200);
    stopButton->move(855,290);
    startButton->setStyleSheet(style);
    stopButton->setStyleSheet(style);


    //播放游戏开始时背景音乐的QSound对象
    sound = new QSound(":/resource/Trepak.wav",this);

    //为开始和暂停按钮绑定槽函数
    connect(startButton,&QPushButton::clicked,[=](){
        //如果已经启动游戏了什么都不干
        if(isGameStart == true) return;

        //如果玩家已经死亡了，new一个新的gameRoom
        if(GameOver == true){
            //关闭当前窗口
            this->close();


            gameRoom *gameroom = new gameRoom;
            gameroom->setAttribute(Qt::WA_DeleteOnClose);
            gameroom->show();

        }
        //启动游戏
        isGameStart = true;
        //启动定时器
        timer->start(snakeMovementSpeed); //timerout事件设置为蛇的移动速度

        //播放背景音乐
        sound->setLoops(-1);//设置播放次数，-1代表循环播放
        sound->play();
    });

    connect(stopButton,&QPushButton::clicked,[=](){
        //如果已经暂停游戏了，什么都不干
        if(isGameStart == false) return;
        //暂停游戏
        isGameStart = false;
        //暂停定时器
        timer->stop();
        //关闭背景音乐
        sound->stop();
    });


    //创建控制方向按钮
    QPushButton *upButton = new QPushButton(this);
    QPushButton *downButton = new QPushButton(this);
    QPushButton *leftButton = new QPushButton(this);
    QPushButton *rightButton = new QPushButton(this);
    upButton->setIcon(QIcon(":/resource/ctrl/up.png"));
    downButton->setIcon(QIcon(":/resource/ctrl/down.png"));
    leftButton->setIcon(QIcon(":/resource/ctrl/left.png"));
    rightButton->setIcon(QIcon(":/resource/ctrl/right.png"));
    upButton->move(880,480);
    downButton->move(880,560);
    leftButton->move(840,520);
    rightButton->move(920,520);
    //设置qss
    upButton->setStyleSheet(style);
    leftButton->setStyleSheet(style);
    rightButton->setStyleSheet(style);
    downButton->setStyleSheet(style);

    //为控制方向按钮创建快捷键
    QShortcut *upShortcut = new QShortcut(QKeySequence(Qt::Key_W),this);
    QShortcut *downShortcut = new QShortcut(QKeySequence(Qt::Key_S),this);
    QShortcut *leftShortcut = new QShortcut(QKeySequence(Qt::Key_A),this);
    QShortcut *rightShortcut = new QShortcut(QKeySequence(Qt::Key_D),this);

    connect(upShortcut,&QShortcut::activated,[=](){
        upButton->clicked();
    });

    connect(downShortcut,&QShortcut::activated,[=](){
        downButton->clicked();
    });

    connect(leftShortcut,&QShortcut::activated,[=](){
        leftButton->clicked();
    });

    connect(rightShortcut,&QShortcut::activated,[=](){
        rightButton->clicked();
    });

    //为四个方向控制按钮绑定槽函数
    connect(upButton,&QPushButton::clicked,[=](){
        if(isGameStart){
            if(snakeDirection != Direction::DOWN){
                //不支持掉头操作
                snakeDirection = Direction::UP;
            }
        }
    });

    connect(downButton,&QPushButton::clicked,[=](){
        if(isGameStart){
            if(snakeDirection != Direction::UP){
                //不支持掉头操作
                snakeDirection = Direction::DOWN;
            }
        }
    });

    connect(leftButton,&QPushButton::clicked,[=](){
        if(isGameStart){
            if(snakeDirection != Direction::RIGHT){
                //不支持掉头操作
                snakeDirection = Direction::LEFT;
            }
        }
    });

    connect(rightButton,&QPushButton::clicked,[=](){
        if(isGameStart){
            if(snakeDirection != Direction::LEFT){
                //不支持掉头操作
                snakeDirection = Direction::RIGHT;
            }
        }
    });


    //创建退出游戏按钮
    QPushButton *backButton = new QPushButton("退出游戏",this);
    backButton->move(830,700);
    backButton->setStyleSheet(style);

    //为退出游戏按钮绑定槽函数
    connect(backButton,&QPushButton::clicked,[=](){

        //显示一个QMessageBox
        QMessageBox *messageBox = new QMessageBox;
        messageBox->setIcon(QMessageBox::Information);
        messageBox->setText("确定要退出游戏嘛？");
        messageBox->setWindowTitle("退出游戏");
        messageBox->setFixedSize(400,400);
        //为消息框添加两个按钮，供用户选择
        QPushButton *ok = new QPushButton("辣鸡游戏，不玩了");
        QPushButton *cancel = new QPushButton("再玩一会");
        messageBox->addButton(ok,QMessageBox::AcceptRole);
        messageBox->addButton(cancel,QMessageBox::RejectRole);
        //模态对话框
        messageBox->exec();

        if(messageBox->clickedButton() == ok){
            //用户点击了ok按钮

            this->setAttribute(Qt::WA_DeleteOnClose);
            //关闭当前窗口
            this->close();

            //回到游戏选择界面
            gameSelect *gameselect = new gameSelect;
            gameselect->setAttribute(Qt::WA_DeleteOnClose);
            gameselect->show();


        }else if(messageBox->clickedButton() == cancel){
            //关闭消息框
            messageBox->close();

            messageBox->deleteLater();
        }

        //音效
        QSound::play(":/resource/clicked.wav");
    });


}

//重写绘制事件绘制游戏房间的背景
void gameRoom::paintEvent(QPaintEvent *event)
{
    //消除告警
    (void)event;

    //创建绘画者
    QPainter painter(this); //这里的this,不是指定父节点挂到对象树上，而是指定绘画的设备，这里我们要往this,也就是widget上绘画

    //创建游戏区域图片对象
    QPixmap pixmap(":/resource/game_room.png"); //要绘制的背景图片

    //绘制游戏区域
    painter.drawPixmap(0,0,800,this->height(),pixmap); //绘制出图片的大小需要和窗口的宽高一致

    //加载控制区域图片对象
    pixmap.load(":/resource/bg1.png");

    //绘制控制区域
    painter.drawPixmap(800,0,200,this->height() + 20,pixmap); //这里高度+20是为了解决留白问题

    //绘制食物
    pixmap.load(":/resource/food.bmp");
    painter.drawPixmap(food->x(),food->y(),foodWidget,foodHeight,pixmap);

    //绘制蛇

    //1.绘制蛇头
    //判断蛇的移动方向
    if(snakeDirection == Direction::UP){
        pixmap.load(":/resource/up.png");
    }else if(snakeDirection == Direction::DOWN){
        pixmap.load(":/resource/down.png");
    }else if(snakeDirection == Direction::LEFT){
        pixmap.load(":/resource/left.png");
    }else if(snakeDirection == Direction::RIGHT){
        pixmap.load(":/resource/right.png");
    }

    //开始绘制
    QRectF snakeHead = snakeList.front();
    painter.drawPixmap(snakeHead.x(),snakeHead.y(),snakeNodeWidget,snakeNodeHeight,pixmap);

    //2.绘制蛇身体
    pixmap.load(":/resource/Bd.png");
    //遍历链表绘制每一个蛇节点 这里i从1开始是因为蛇头我们已经绘制了，size()-1是因为蛇尾巴我们单独绘制
    for(int i = 1;i < snakeList.size() - 1;i++){
        QRectF body = snakeList.at(i);
        painter.drawPixmap(body.x(),body.y(),snakeNodeWidget,snakeNodeHeight,pixmap);
    }

    //绘制蛇尾巴
    pixmap.load(":/resource/Bd.png");
    QRectF snakeTail = snakeList.back();
    painter.drawPixmap(snakeTail.x(),snakeTail.y(),snakeNodeWidget,snakeNodeHeight,pixmap);

    //绘制积分
    //积分背景图片
    pixmap.load(":/resource/sorce_bg.png");
    painter.drawPixmap(this->width() * 0.82,this->height() * 0.06,150,70,pixmap);

    //积分图标
//    pixmap.load(":/resource/scores.png");
//    painter.drawPixmap(this->width() * 0.80,this->height() * 0.09,90,42,pixmap);

    //积分
    QFont font("华文行楷",30);
    painter.setPen(Qt::red);
    painter.setFont(font);
    //以蛇的节点来计算积分 -3是初始化的时候蛇的节点为3
    painter.drawText(QRect(this->width() * 0.9,this->height() * 0.09,100,100),QString::number(snakeList.size() - 3));


    //绘制游戏结束效果
    if(isGameOver() == true){
        //暂停游戏
        isGameStart = false;

        //玩家已死亡
        GameOver = true;

        //绘制game over效果
        QFont font("黑体",30);
        painter.setFont(font);
        painter.drawText(QRect(this->width() * 0.2 , this->height() * 0.5 , 800,400),"Game Over!!!");

        //停止定时器
        timer->stop();

        //暂停背景音乐
        sound->stop();

        //使用count变量解决绘制事件多次调用，导致多次写入数据的问题
        if(this->count == 0){
            //播放gameover音效
            QSound::play(":/resource/gameover.wav");

            //往历史记录文件中写入日志
            //获取当前系统时间
            QString log = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") + " ,难度： " + convert(gameDifficulty) + ", 得分：" + QString::number(snakeList.size() - 3) + '\n';
            utility::WriteFile("C:/Users/LKM/Code/snake-game/Snake/history/historyScore.txt",log);
        }

        this->count++;
    }
}


void gameRoom::moveTop()
{
     //通过左上和右下两个点就可以确定一个唯一的QRectF矩形
     QPoint leftTop; //左上的坐标
     QPoint rightButtom; //右下的坐标

     //1.获取蛇头的左上坐标
     QRectF snakeHead = snakeList.front();
     int headX = snakeHead.x();
     int headY = snakeHead.y();

     //2.判断蛇头位置向上移动后的坐标
     if(headY - snakeNodeHeight < 0){
         //撞墙了的情况
         leftTop = QPoint(headX,(this->height() - snakeNodeHeight));
     }else{
         leftTop = QPoint(headX,headY - snakeNodeHeight);
     }

     //右下坐标永远等于左上坐标加上蛇节点的宽高
     rightButtom = leftTop + QPoint(snakeNodeWidget,snakeNodeHeight);

     //3.构建新节点
     QRectF newNode(leftTop,rightButtom);

     //4.头插进蛇链表
     snakeList.push_front(newNode);
}

void gameRoom::moveDown()
{
    //通过左上和右下两个点就可以确定一个唯一的QRectF矩形
     QPoint leftTop; //左上的坐标
     QPoint rightButtom; //右下的坐标

     //1.获取蛇头的左上坐标
     QRectF snakeHead = snakeList.front();
     int headX = snakeHead.x();
     int headY = snakeHead.y();

     //2.判断蛇头位置向下移动后的坐标
     if(headY + snakeNodeHeight > this->height() ){
         //撞墙了的情况
         leftTop = QPoint(headX,0);
     }else{
         leftTop = QPoint(headX,headY + snakeNodeHeight);
     }

     //右下坐标永远等于左上坐标加上蛇节点的宽高
     rightButtom = leftTop + QPoint(snakeNodeWidget,snakeNodeHeight);

     //3.构建新节点
     QRectF newNode(leftTop,rightButtom);

     //4.头插进蛇链表
     snakeList.push_front(newNode);

}

void gameRoom::moveLeft()
{
    //通过左上和右下两个点就可以确定一个唯一的QRectF矩形
     QPoint leftTop; //左上的坐标
     QPoint rightButtom; //右下的坐标

     //1.获取蛇头的左上坐标
     QRectF snakeHead = snakeList.front();
     int headX = snakeHead.x();
     int headY = snakeHead.y();

     //2.判断蛇头位置向左移动后的坐标
     if(headX - snakeNodeWidget < 0 ){
         //撞墙了的情况
         leftTop = QPoint(800 - snakeNodeWidget,headY);
     }else{
         leftTop = QPoint(headX - snakeNodeWidget,headY);
     }

     //右下坐标永远等于左上坐标加上蛇节点的宽高
     rightButtom = leftTop + QPoint(snakeNodeWidget,snakeNodeHeight);

     //3.构建新节点
     QRectF newNode(leftTop,rightButtom);

     //4.头插进蛇链表
     snakeList.push_front(newNode);


}

void gameRoom::moveRight()
{
    //通过左上和右下两个点就可以确定一个唯一的QRectF矩形
     QPoint leftTop; //左上的坐标
     QPoint rightButtom; //右下的坐标

     //1.获取蛇头的左上坐标
     QRectF snakeHead = snakeList.front();
     int headX = snakeHead.x();
     int headY = snakeHead.y();

     //2.判断蛇头位置向右移动后的坐标
     if(headX + snakeNodeWidget > 780 ){ //改成780是为了解决右移动撞墙时会蛇会穿墙的bug
         //撞墙了的情况
         leftTop = QPoint(0,headY);
     }else{
         leftTop = QPoint(headX + snakeNodeWidget,headY);
     }

     //右下坐标永远等于左上坐标加上蛇节点的宽高
     rightButtom = leftTop + QPoint(snakeNodeWidget,snakeNodeHeight);

     //3.构建新节点
     QRectF newNode(leftTop,rightButtom);

     //4.头插进蛇链表
     snakeList.push_front(newNode);

}

bool gameRoom::isGameOver()
{
    QRectF snakeHead = snakeList.front(); //蛇头
    for(int i = 1;i < snakeList.size();i++){
        if(snakeList.at(i).intersects(snakeHead)){
            //如果蛇头等于蛇身就代表游戏结束
            return true;
        }
    }

    return false;
}

void gameRoom::setMovementSpeed(int speed)
{
    this->snakeMovementSpeed = speed;
}

void gameRoom::setGameDifficulty(Difficulty difficulty)
{
    this->gameDifficulty = difficulty;
}

QString gameRoom::convert(Difficulty difficulty)
{
    if(difficulty == Difficulty::simple){
        return "简单";
    } else if(difficulty == Difficulty::mormal){
        return "普通";
    }else {
        return "困难";
    }
}
